iT邦幫忙

2022 iThome 鐵人賽

DAY 29
2
Modern Web

Nuxt 3 學習筆記系列 第 29 篇

[Day 29] Nuxt 3 發布網站前的建構打包 (Build) 與靜態網站生成 (Static Site Generation)

  • 分享至 

  • xImage
  •  

Vue.js → Nuxt 入門書籍推薦.《想要 SSR 嗎?就使用 Nuxt 吧!Nuxt 讓 Vue.js 更好處理 SEO 搜尋引擎最佳化》

🔥【Vue.js → Nuxt 入門推薦!🌟 新書即將上市 🌟】
📘《想要 SSR 嗎?就使用 Nuxt 吧!Nuxt 讓 Vue.js 更好處理 SEO 搜尋引擎最佳化》
👀 Nuxt v4 內容與範例也可以參考並購買本系列文筆著所著書籍
📦 預計於:2025/08/14 出版,目前天瓏書局預購有 7️⃣8️⃣ 折優惠
👉 點此前往購買:https://pse.is/7yulm5

注意:Nuxt 4 已於 2025/07/16 釋出,本文部分內容或範例可能和最新版本有所不同

前言

當網站開發完成或有導入 CI/CD,在準備發布網站前,我們會將 Nuxt 網站的開發專案透過 Nuxt 提供的指令,我們可以來建構出正式環境所需要的版本,這個建構的過程你可以理解為專案將會打包需要的依賴套件、編譯與轉換相關的 Vue SFC 與樣式等,甚至幫你壓縮這些檔案等許多步驟,這些繁瑣的過程都透過 Nuxt 的建構指令來幫你完成,你可以結合一些設定參數與指令,來幫助你建構出正式環境所需要的網站專案,最後再進行部署的動作。

Nuxt 3 專案如何建構正式環境版本

當我們建立一個乾淨的 Nuxt 3 專案,可以使用 package.json 中 scripts 內的指令來進行建構或預渲染產生靜態頁面。

  • npm run build
  • npm run generate

或者你也可以使用 Nuxt CLI 來達到一樣的效果

  • npx nuxi build
  • npx nuxi generate

generate 指令會觸發 build 的指令並帶有 prerender 為 true 的參數,最終產生出來的目錄可以直接進行部署,不需要再執行一次 build 的指令。

使用預設配置進行建構 - 建構通用渲染 (Universal Rendering) 的網站

這邊我們以這個系列文章所建立的部落格作為範例,來嘗試以預設的配置進行建構,目前 Nuxt 3 預設 nuxt.config.ts 中 ssr 屬性為 true,也就使用通用渲染 (Universal Rendering)。

我們進入專案目錄,執行下列指令:

npm run build

不需要在額外的配置或步驟,Nuxt 就會自動幫我們打包並建構出可以部署的網站。
https://i.imgur.com/tsHV41j.gif

建構完成後會在專案目錄下多出一個 .output 目錄,public 就是在網站根目錄直接公開打包後的 JS、CSS 圖片等相關檔案。由於通用渲染使用 Nitro 作為服務引擎,所以會需要使用 Node.js 來啟動我們的服務,所以server 則是會放置伺服器端的 Nitro、Server API 處理邏輯等。
https://ithelp.ithome.com.tw/upload/images/20221014/20152617yAGBjPZ3Hf.png

我們可以先在本地執行下列指令來預覽建構出來的網站與 Nitro 是否能運作正常。

node .output/server/index.mjs

當確認沒問題後,就能以 .output 目錄進行網站部署。

使用預渲染建置全靜態頁面網站

在前一篇文章有提到,我們可以在 Nuxt 3 建構時期來進行預渲染 (pre-rendering),將專案內需要打 API 請求及動態渲染元件的地方,先渲染生成出 HTML 網頁,這個過程也稱之為靜態網站生成 (Static Site Generation),進而建構出全靜態頁面的網站。

執行下列指令進行靜態頁面生成:

npm run generate

generate 指令會觸發build 的指令並帶有 prerender 為 true 的參數,最終會提示產生的目錄 .output/public 可以用來部署至靜態託管伺服器。
https://i.imgur.com/sWAK0uu.gif

當建構完成後,會在專案目錄下多出一個 .output 目錄同時也會有 dist 目錄,可以發現 .output/public 目錄內容與 dist 目錄相同。
https://ithelp.ithome.com.tw/upload/images/20221014/2015261766kiDKvwgH.png

靜態頁面的生成因為Nuxt 使用基於爬蟲的技術為每個頁面產生 HTML 與 Payload 檔案,可以發現產生的靜態頁面目錄結構,也對應著我們專案的路由頁面,而頁面元件資料夾內會由一個 index.html 與 _payload.js 組成。

下圖所產生的結構,是因為我們的部落格資料庫內已經有三筆文章資料,/articles 頁面會取得所有的文章,並列出對應著 /articles/1、/articles/2 與 /articles/3 目錄,每個頁面內也都包含預先從 Server API 請求好的文章資料並存於 _payload.js 之中。
https://ithelp.ithome.com.tw/upload/images/20221014/20152617jEaXCTMEYH.png

至此我們就可以將 .output 目錄部署至伺服器或靜態託管服務,而且也不需要在使用 Node.js 伺服器來服務這些靜態檔案。

手動設定預渲染的路由規則

我們使用 generate 指令所產生的全靜態頁面網站,是基於 Nuxt 的爬蟲技術來分析頁面,如同前個例子文章頁面的產生所描述,如果我們的資料庫存在著 200 筆資料,但 /articles 頁面所打的 API 總是只回傳最新的 10 筆,那麼那些沒有路由連結可以連結過去的文章頁面,就無法被 Nuxt 的爬蟲所分析到,也就無法產生對應的靜態頁面。

為了解決這個問題,我們可以藉由配置 Nitro 的預渲染路由,來手動的設定哪些頁面要進行預渲染產生靜態頁面,或者忽略產生靜態頁面。

export default defineNuxtConfig({
  nitro: {
    prerender: {
      ignore: [],       // 忽略特定路由不進行預渲染
      routes: [],       // 指定路由進行預渲染
      crawlLinks: true  // 啟用 Nuxt 爬蟲蒐集頁面連結來進行預渲染
    }
  }
})

當然,也可以搭配 build 或 generate 指令做使用,但會稍微有些不一樣。

build

例如,設置如下,並使用 npm run build 指令。

export default defineNuxtConfig({
  nitro: {
    prerender: {
      routes: ['/articles', '/articles/2']
    }
  }
})

那麼建構出來的通用渲染網站,就會包含部分頁面是已經預渲染好的靜態頁面。
https://ithelp.ithome.com.tw/upload/images/20221014/20152617Wim98mAvMu.png

generate

當我們使用 generate 時,因為是進行全站的靜態頁面生成,所以基本上涵蓋了所有路由頁面,並且 nitro.prerender.crawlLinks 屬性預設為 true 會啟用 Nuxt 爬蟲來蒐集整的網站的路由頁面,進而開始預渲染產生靜態頁面。

例如,設置如下,並使用 npm run generate 指令。

export default defineNuxtConfig({
  nitro: {
    prerender: {
      ignore: ['/login', '/register'],
      routes: ['/articles/2'],
      crawlLinks: true
    }
  },
})

那麼建構出來的 .output 目錄,就會因為設置了 nitro.prerender.ignore 而忽略 /login 與 /register 頁面的靜態生成 ,而 /articles/2 在網站中因為沒有任何頁面能連結到此,所以 Nuxy 爬蟲無法蒐集到,所以可以手動添加進 nitro.prerender.routes 職中。
https://ithelp.ithome.com.tw/upload/images/20221014/20152617Dint78UWr5.png

如果我們將 nitro.prerender.crawlLinks 屬性設為 false,那麼在產生靜態頁面的時候,就算 /articles 包含了所有文章的連結,Nuxt 爬蟲也就不會蒐集連結來產生靜態頁面,而是僅依照專案目錄下的 pages 所產生出的路由但不包含 [id].vue 這類動態匹配的路由來產生靜態頁面。

建構僅在客戶端渲染的網站

同樣的使用部落格作為範例,來嘗試將 nuxt.config.ts 中 ssr 屬性設為 fasle,也就讓網站僅在客戶端渲染 (Client-side Only Rendering)。

執行下列指令進行建構:

npm run build

建構完成後,會在專案目錄下多出一個 .output 目錄,可以發現 public 目錄結構與通用渲染建構出的不大一樣,多出了像 Vue 專案建構完成後的 index.html 檔案,來作為顯示的容器。
https://ithelp.ithome.com.tw/upload/images/20221014/20152617UTVKL4Ne4z.png

這邊比較需要留意的地方是,當我們將 ssr 屬性設為 fasle,也還是會在 .output 建構出 server 目錄,也擁有著 .output/server/index.mjs。

那這不就意謂著我還是得有 Node.js 服務才能部署嗎?其實你可以這麼理解,當我們設定 Nuxt 僅在客戶端進行渲染,但 Nuxt 專案中仍然可能有Server API,這個屬於伺服器端的 API,總不可能一同打包至前端去做架設吧!所以使用 npm run build 建構出來的專案,都會使用 Nitro 引擎來啟動服務,若有 Server API 的處理邏輯,則會連帶打包進 .output/server 目錄之下。

如果你確定 Nuxt 的專案內沒有自己實作的 Server API,全部是依賴非專案內的 Server API,那麼你可以直接將 public 目錄,視為 Vue 建構出的 dist 目錄來進行部署,因為選擇不再需要 Nitro 引擎來為我們提供 Web Server 的服務,且專案內的前端也都打包完在 public 下可以視為 SPA 網站。

整理這些排列建構參數的組合

相信看到這裡,可能對建構與產生靜態頁面有一點混亂了,這邊稍微整理了一下,大家可以再依據需求來啟用相對應的配置。

npm run build + ssr: true

build + ssr: true

Nuxt 3 預設的建構參數,使用通用渲染 (Universal Rendering) 模式。

build + ssr: true + nitro.prerender.crawlLinks: true

使用通用渲染模式,頁面中需要打 API 動態產生的連結而被 Nuxt 爬蟲所蒐集到的頁面將被預渲染成靜態頁面。

build + ssr: true + nitro.prerender.routes + nitro.prerender.crawlLinks: false

使用通用渲染模式,但指定頁面預渲染成靜態頁面。

npm run build + ssr: false

build + ssr: false

僅在客戶端渲染 (Client-side Only Rendering) 的模式,部署時同樣需要使用 server 中的 index.mjs 來啟動 Nitro 伺服器,這樣才能正確的運作 Server API;除非確認專案內完全無依賴專案內的 Server API,則可以直接將 .output/public 視為 Vue 的 dist 目錄進行部署。

npm run generate + ssr: true

generate + ssr: true

使用預渲染產生靜態頁面,預設產生全站靜態頁面,generate 下 nitro.prerender.crawlLinks 屬性預設變為 true,整個網站包含 Nuxt 爬蟲所蒐集到的頁面將被預渲染成靜態頁面。

generate + ssr: true + nitro.prerender.ignore

使用 generate 已經包含整個網站,如果想要忽略某些頁面進行預渲染,可以添加路由至 nitro.prerender.ignore 中。但是需要注意,這些被忽略的頁面如果有使用專案內的 Server API 需求,可能就無法正確的在靜態託管平台運作,而外部的倒是不受影響。

generate + ssr: true + nitro.prerender.routes

雖然使用 generate 已經包含整個網站,但 Nuxt 爬蟲所蒐集到的頁面僅為頁面中產生的,如果連結不存在這些頁面內,只能只接從瀏覽器網址列輸入進入,那麼我們可以將路由添加至 nitro.prerender.routes 來額外補充需要預渲染的頁面。

generate + ssr: true + nitro.prerender.routes + nitro.prerender.crawlLinks: false

同樣會產生全站靜態頁面,但不使 Nuxt 爬蟲所蒐集到的連結頁面,所以這些動態匹配或需要打 API 獲取資料再渲染的頁面,將不會是靜態頁面,因此也需要注意,如果這些頁面有使用專案內的 Server API 需求,可能就無法正確的在靜態託管平台運作,而外部的倒是不受影響。

其它跟建構有關的參數屬性可以再參考官方文件,Vite 與 webpack 建構工具也都能額外設定參數屬性。

小結

Nuxt 的建構指令 build 與產生靜態頁面的 generate 指令,讓我們可以依據不同的情境來決定渲染模式與預渲染的頁面,最終產生的 .output 目錄也會有不一樣的結構。預渲染的頁面與單純的 SPA 也要注意使否有使用到 Nuxt 專案建立的 Server API,再決定是否需要 Nitro 伺服器來啟動正式環境的網站服務。當一切就緒之後最後就能將輸出的目錄打包進行部署。


感謝大家的閱讀,這是我第一次參加 iThome 鐵人賽,請鞭小力一些,也歡迎大家給予建議 :)
如果對這個 Nuxt 3 系列感興趣,可以訂閱接收通知,也歡迎分享給喜歡或正在學習 Nuxt 3 的夥伴。

範例程式碼

參考資料

Vue.js → Nuxt 入門書籍推薦.《想要 SSR 嗎?就使用 Nuxt 吧!Nuxt 讓 Vue.js 更好處理 SEO 搜尋引擎最佳化》


上一篇
[Day 28] Nuxt 3 渲染模式 (Rendering modes) 與網站使用體驗核心指標 (Core Web Vitals)
下一篇
[Day 30] Nuxt 3 就剩最後一步了 - 部署 (Deployment)
系列文
Nuxt 3 學習筆記 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言